package com.yubest.jsr269;

import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Names;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.Random;
import java.util.Set;

/**
 * 作用：给bean添加一个自定义的serialVersionUid字段
 * @Author: hweiyu
 * @Date: 2024/3/1 10:56
 */
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("com.yubest.jsr269.SerialVersionUid")
public class SerialVersionUidProcessor extends AbstractProcessor {

    /**
     * 编译时期输入日志的
     */
    private Messager messager;

    /**
     * 将Element转换为JCTree的工具,提供了待处理的抽象语法树
     */
    private JavacTrees javacTrees;

    /**
     * 封装了创建AST节点的一些方法
     */
    private TreeMaker treeMaker;

    /**
     * 提供了创建标识符的方法
     */
    private Names names;

    private static final String SERIAL_VERSION_UID_NAME = "serialVersionUID";

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.messager = processingEnv.getMessager();
        this.javacTrees = JavacTrees.instance(processingEnv);
        Context context = ((JavacProcessingEnvironment)processingEnv).getContext();
        this.treeMaker = TreeMaker.instance(context);
        this.names = Names.instance(context);
    }

    @Override
    public synchronized boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(SerialVersionUid.class);
        for (Element element : elements) {
            JCTree tree = javacTrees.getTree(element);
            tree.accept(new TreeTranslator() {
                @Override
                public void visitClassDef(JCTree.JCClassDecl jcClassDecl) {
                    // 用于判断类中，是否已经存在serialVersionUID属性了
                    boolean hasSerialVersionUid = false;
                    for (JCTree def : jcClassDecl.defs) {
                        if (def.getKind().equals(Tree.Kind.VARIABLE)) {
                            JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) def;
                            if (SERIAL_VERSION_UID_NAME.equals(jcVariableDecl.getName().toString())) {
                                hasSerialVersionUid = true;
                                break;
                            }
                        }
                    }
                    if (!hasSerialVersionUid) {
                        JCTree.JCVariableDecl serialVersionUID = createSerialVersionUid();
                        jcClassDecl.defs = jcClassDecl.defs.prepend(serialVersionUID);
                    }
                    super.visitClassDef(jcClassDecl);
                }
            });
        }

        return true;
    }

    private JCTree.JCVariableDecl createSerialVersionUid() {
        return treeMaker.VarDef(treeMaker.Modifiers(Flags.PRIVATE + Flags.FINAL + Flags.STATIC),
                names.fromString(SERIAL_VERSION_UID_NAME),
                treeMaker.Ident(names.fromString("Long")),
                treeMaker.Literal(new Random().nextLong()));
    }
}
